﻿/*
* File:        jquery.dataTables.editable.js
* Version:     1.0.0
* Author:      Jovan Popovic 
* 
* Copyright 2010-2011 Jovan Popovic, all rights reserved.
*
* This source file is free software, under either the GPL v2 license or a
* BSD style license, as supplied with this software.
* 
* This source file is distributed in the hope that it will be useful, but 
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
* or FITNESS FOR A PARTICULAR PURPOSE. 
* 
* Parameters:
* @sDetailsURL                  String      
* @sUpdateURL                   String      URL of the server-side page used for updating cell. Default value is "UpdateData".
* @sAddURL                      String      URL of the server-side page used for adding new row. Default value is "AddData".
* @sDeleteURL                   String      URL of the server-side page used to delete row by id. Default value is "DeleteData".
* @onRowDoubleClick
* @sAddNewRowFormId             String      Id of the form for adding new row. Default id is "formAddNewRow".
* @sAddNewRowButtonId           String      Id of the button for adding new row. Default id is "btnAddNewRow".
* @sAddNewRowOkButtonId         String      Id of the OK button placed in add new row dialog. Default value is "btnAddNewRowOk".
* @sAddNewRowCancelButtonId     String      Id of the OK button placed in add new row dialog. Default value is "btnAddNewRowCancel".
* @sDeleteRowButtonId           String      Id of the button for adding new row. Default id is "btnDeleteRow".
* @sToolbarId                   String      Selector used to identify place where add and delete buttons should be placed. Default value is ".add_delete_toolbar".

* @sSelectedRowClass            String      Class that will be associated to the selected row. Default class is "row_selected".
* @sReadOnlyCellClass           String      Class of the cells that should not be editable. Default value is "read_only".
* @fnStartProcessingMode        Function    function(){...} called when AJAX call is started. Use this function to add "Please wait..." message  when some button is pressed.
* @fnEndProcessingMode          Function    function(){...} called when AJAX call is ended. Use this function to close "Please wait..." message.
* @fnShowError                  Function    function(message, action){...}  used to show error message. Action value can be "update", "add" or "delete".
* @aoColumns                    Array       Array of the JEditable settings that will be applied on the columns
*/
(function ($) {
    //静态成员，只读属性。如果不是只读，则同一个页面内将只能有一个DataTable
    //Plugin options
    var properties;

    ///Utility function used to determine id of the cell
    //By default it is assumed that id is placed as an id attribute of <tr> that that surround the cell (<td> tag). E.g.:
    //<tr id="17">
    //  <td>...</td><td>...</td><td>...</td><td>...</td>
    //</tr>
    function fnGetCellID(cell) {
        return properties.fnGetRowID($(cell.parentNode));
    }

    /// Utility function that shows an error message
    ///@param errorText - text that should be shown
    ///@param action - action that was executed when error occured e.g. "update", "delete", or "add"
    function _fnShowError(errorText, action) {
        alert(errorText);
    }
    ///Utility function used to set id of the new row
    //It is assumed that id is placed as an id attribute of <tr> that that surround the cell (<td> tag). E.g.:
    //<tr id="17">
    //  <td>...</td><td>...</td><td>...</td><td>...</td>
    //</tr>
    function _fnSetRowIDInAttribute(row, id) {
        row.attr("id", id);
    }

    //Utility function used to get id of the row
    //It is assumed that id is placed as an id attribute of <tr> that that surround the cell (<td> tag). E.g.:
    //<tr id="17">
    //  <td>...</td><td>...</td><td>...</td><td>...</td>
    //</tr>
    function _fnGetRowIDFromAttribute(row) {
        return row.attr("id");
    }

    //Utility function used to set id of the new row
    //It is assumed that id is placed as an id attribute of <tr> that that surround the cell (<td> tag). E.g.:
    //<tr>
    //  <td>17</td><td>...</td><td>...</td><td>...</td>
    //</tr>
    function _fnSetRowIDInFirstCell(row, id) {
        $("td:first", row).html(id);
    }

    //Utility function used to get id of the row
    //It is assumed that id is placed as an id attribute of <tr> that that surround the cell (<td> tag). E.g.:
    //<tr>
    //  <td>17</td><td>...</td><td>...</td><td>...</td>
    //</tr>
    function _fnGetRowIDFromFirstCell(row) {
        var ret = $("td:first", row).html();
        return ret;
    }

    $.fn.makeEditable = function (options) {
        //Called when record is deleted on the server
        function fnOnRowDeleted(response) {
            properties.fnEndProcessingMode();
            var oTRSelected = $('tr.' + properties.sSelectedRowClass, oTable)[0];
            if (response == "ok" || response == "") {
                oTable.fnDeleteRow(oTRSelected);
                oDeleteRowButton.button("disable");
            }
            else {
                properties.fnShowError(response, "delete");
            }
        }
        function fnOnRowAdded(data) {
            properties.fnEndProcessingMode();

            var iColumnCount = oTable.dataTableSettings[0].aoColumns.length;
            var values = new Array();

            $("input:text[rel],input:radio[rel][checked],select[rel],textarea[rel]", oAddNewRowForm).each(function () {
                var rel = $(this).attr("rel");
                if (rel >= iColumnCount)
                    properties.fnShowError("In the add form is placed input element with the name '" + $(this).attr("name") + "' with the 'rel' attribute that must be less than a column count - " + iColumnCount, "add");
                else
                    values[rel] = this.value;
            });

            //Add values from the form into the table
            var rtn = oTable.fnAddData(values);
            var oTRAdded = oTable.fnGetNodes(rtn);
            //Apply editable plugin on the cells of the table
            fnApplyEditable(oTRAdded);
            //add id returned by server page as an TR id attribute
            properties.fnSetRowID($(oTRAdded), data);
            //Close the dialog
            oAddNewRowForm.dialog('close');
            $(oAddNewRowForm)[0].reset();
            $(".error", $(oAddNewRowForm)).html("");
        }

        //Utility function that put the table into the "Processing" state
        function _fnStartProcessingMode() {
            if (oTable.fnSettings().oFeatures.bProcessing) {
                $(".dataTables_processing").css('visibility', 'visible');
                //$(".dataTables_processing").show();
            }
        }

        //Utility function that put the table in the normal state
        function _fnEndProcessingMode() {
            if (oTable.fnSettings().oFeatures.bProcessing) {
                $(".dataTables_processing").css('visibility', 'hidden');
                //$(".dataTables_processing").hide();
            }
        }

        var oTable = this;

        properties = {
            fnGetRowID: _fnGetRowIDFromAttribute,
            fnSetRowID: _fnSetRowIDInAttribute,
            height: "14px",
            sSelectedRowClass: "row_selected",
            sReadOnlyCellClass: "read_only",
            fnShowError: _fnShowError,
            fnStartProcessingMode: _fnStartProcessingMode,
            fnEndProcessingMode: _fnEndProcessingMode,
            aoColumns: null
        };


        return this.each(function () {
            var _oToolbar;
            if (options.sToolbarId == null)
                return;
            else {
                _oToolbar = $("#" + options.sToolbarId);
                if (_oToolbar.length == 0)
                    return;
            }

            //如果table设置了serverSide则为table行添加id属性
            if (oTable.fnSettings().oFeatures.bServerSide) {
                oTable.fnSettings().aoDrawCallback.push({
                    "fn": function () {

                        $(oTable.fnGetNodes()).each(function () {
                            var position = oTable.fnGetPosition(this);
                            var id = oTable.fnGetData(position)[0];
                            //如果给定了DetailsFormId则为table行添加双击打开details窗口事件
                            if (options.onRowDoubleClick != null) {
                                $(this).dblclick(function () {
                                    options.onRowDoubleClick(id);
                                });
                            }
                            properties.fnSetRowID($(this), id);
                        }
                        );
                    },
                    "sName": "fnApplyEditable"
                });
            }

            var oAddNewRowForm;
            //如果给定了AddNewRowFormId 和 AddNewRowButtonId 则为table添加 新建 功能
            if (options.sAddNewRowFormId != null && options.sAddNewRowButtonId != null) {
                oAddNewRowForm = $("#" + options.sAddNewRowFormId);
                if (oAddNewRowForm.length != 0) {
                    oAddNewRowForm.dialog({ autoOpen: false });

                    //Add button click handler on the "Add new row" button
                    var oAddNewRowButton = $("#" + options.sAddNewRowButtonId);
                    if (oAddNewRowButton.length == 0) {
                        _oToolbar.append("<button id='" + options.sDeleteRowButtonId + "'>删除</button>");
                        oDeleteRowButton = $("#" + options.sDeleteRowButtonId).button();
                    }
                    oAddNewRowButton.click(function () { oAddNewRowForm.dialog('open'); });
                    oConfirmRowAddingButton = $("#" + options.sAddNewRowOkButtonId, oAddNewRowForm);
                    if (oConfirmRowAddingButton.length == 0) {
                        oAddNewRowForm.append("<button id='" + options.sAddNewRowOkButtonId + "'>确认</button>");
                        oConfirmRowAddingButton = $("#" + options.sAddNewRowOkButtonId, oAddNewRowForm).button();
                    }

                    //Add button click handler on the "Ok" button in the add new row dialog
                    oConfirmRowAddingButton.click(function (event) {
                        if (oAddNewRowForm.valid()) {
                            properties.fnStartProcessingMode();
                            var params = oAddNewRowForm.serialize();
                            $.ajax({ 'url': properties.sAddURL,
                                'data': params,
                                'type': 'POST',
                                success: fnOnRowAdded,
                                error: function (response) {
                                    properties.fnEndProcessingMode();
                                    properties.fnShowError(response.responseText, "add");
                                }
                            });
                        }
                        event.stopPropagation();
                        event.preventDefault();
                    });

                    oCancelRowAddingButton = $("#" + options.sAddNewRowCancelButtonId);
                    if (oCancelRowAddingButton.length == 0) {
                        oCancelRowAddingButton = oAddNewRowForm.append("<button id='" + options.sAddNewRowCancelButtonId + "'>取消</button>");
                        oCancelRowAddingButton = $("#" + options.sAddNewRowCancelButtonId).button();
                    }

                    oCancelRowAddingButton.click(function (event) {
                        //Close the dialog
                        oAddNewRowForm.dialog('close');
                        $(oAddNewRowForm)[0].reset();
                        $(".error", $(oAddNewRowForm)).html("");
                        event.stopPropagation();
                        event.preventDefault();
                    });
                } else {
                    throw "AddNewForm不存在";
                }
            }

            //如果给定了DeleteRowButtonId 则为table添加 删除 功能
            var oDeleteRowButton;
            if (options.sDeleteRowButtonId != null) {
                oDeleteRowButton = $("#" + options.sDeleteRowButtonId);
                if (oDeleteRowButton.length == 0) { //如果删除按钮不存在则像toolbar中添加一个
                    _oToolbar.append("<button id='" + options.sDeleteRowButtonId + "'>删除</button>");
                    oDeleteRowButton = $("#" + options.sDeleteRowButtonId).button({
                        text: false,
                        icons: {
                            primary: "ui-icon-closethick"
                        }
                    });
                }
                oDeleteRowButton.click(function (event) {
                    if ($('tr.' + properties.sSelectedRowClass + ' td', oTable).length == 0) {
                        oDeleteRowButton.button("disable");
                        return;
                    }
                    var id = fnGetCellID($('tr.' + properties.sSelectedRowClass + ' td', oTable)[0]);
                    properties.fnStartProcessingMode();
                    $.ajax({ 'url': options.sDeleteURL,
                        'data': 'id=' + id,
                        "success": function (response) {
                            properties.fnEndProcessingMode();
                            var oTRSelected = $('tr.' + properties.sSelectedRowClass, oTable)[0];
                            if (response == "ok" || response == "") {
                                oTable.fnDeleteRow(oTRSelected);
                                oDeleteRowButton.button("disable");
                            }
                            else {
                                properties.fnShowError(response, "delete");
                            }
                        },
                        "error": function (response) {
                            properties.fnEndProcessingMode();
                            properties.fnShowError(response.responseText, "delete");

                        }
                    });
                });
                oDeleteRowButton.button("disable");
            }

            //为table行绑定事件
            $("tbody", oTable).click(function (event) {
                var oDeleteRowButton = $("#" + options.sDeleteRowButtonId);
                if ($(event.target.parentNode).hasClass(properties.sSelectedRowClass)) {
                    $(event.target.parentNode).removeClass(properties.sSelectedRowClass);
                    if (oDeleteRowButton != null)
                        oDeleteRowButton.button("disable");
                } else {
                    $(oTable.fnSettings().aoData).each(function () {
                        $(this.nTr).removeClass(properties.sSelectedRowClass);
                    });
                    $(event.target.parentNode).addClass(properties.sSelectedRowClass);
                    if (oDeleteRowButton != null)
                        oDeleteRowButton.button("enable");
                }
            });
        });
    };
})(jQuery);